﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using MediaData;
using System.Threading;

namespace MediaData
{
    public class MediaDataImporter : MediaImporter
    {
        MediaDataSet data;
        FileCache[] caches;

        public MediaDataSet Data
        {
            get { return data; }
            set { data = value; }
        }
        public bool DistributeMetadata { get; set; }


        public MediaDataImporter(MediaRootManager roots, MediaDataSet data, IEnumerable<FileCache> caches)
            : this(roots, data)
        {
            this.caches = caches.ToArray();
        }
        
        public MediaDataImporter(MediaRootManager roots, MediaDataSet data) : base(roots)
        {
            this.data = data;
            BeginCommit += new EventHandler(TestDataImporter_BeginCommit);
            EndCommit += new EventHandler(TestDataImporter_EndCommit);
            DistributeMetadata = true;
        }

        void TestDataImporter_EndCommit(object sender, EventArgs e)
        {
            RemoveUnusedTitles();
            Monitor.Exit(data.LockObject);
        }

        void TestDataImporter_BeginCommit(object sender, EventArgs e)
        {
            Monitor.Enter(data.LockObject);
            lock (data.LockObject)
                UpdateCaches();
        }

        protected override bool ItemExists(MediaData.MediaItem item)
        {
            return data.Files.Rows.Contains(new object[] { item.Volume, MakeDBPath( item )});
        }

        protected override void AddItem(MediaData.MediaItem item)
        {
            MediaDataSet.TitlesRow title = (from t in data.Titles
                                        where t.Name.Equals(item.Title, StringComparison.CurrentCultureIgnoreCase) && t.Type.Equals(item.Type, StringComparison.CurrentCultureIgnoreCase)
                                        select t).FirstOrDefault();

            if (title == null)
            {
                title = data.Titles.AddTitlesRow(item.Title, item.Type, "");
            }


            long time = item.CreationTime > DateTime.Now ? DateTime.Now.ToFileTime() : item.CreationTime.ToFileTime();

            if (item.CreationTime > DateTime.Now)
            {
                try
                {
                    File.SetLastWriteTime(item.Path, DateTime.Now);
                }
                catch { }
            }


            MediaDataSet.FilesRow file = data.Files.AddFilesRow(item.Volume, MakeDBPath(item), title, DateTime.Now.Date.ToFileTime(), time);


            if (item.LastEpisode <= 0)
                item.LastEpisode = item.Episode;

            if (item.Episode != 0)
                for (int i = item.Episode; i <= item.LastEpisode; i++)
                {
                    MediaDataSet.EpisodesRow episode = (from e in title.GetEpisodesRows()
                                                    where e.Episode == i && e.Season == item.Season
                                                    select e).FirstOrDefault();

                    if (episode == null)
                    {
                        episode = data.Episodes.AddEpisodesRow(title, "", item.Season, i, "", 0);
                    }

                    data.EpisodeFiles.AddEpisodeFilesRow(episode, file.Volume, file.Path);
                }



        }
        private string MakeDBPath(MediaItem item)
        {
            string rootPath = roots[item.Volume];
            return item.Path.Replace(rootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? rootPath : rootPath + Path.DirectorySeparatorChar, "");
        }

        protected override void RemoveItem(MediaData.MediaItem item)
        {
            data.Files.Rows.Find(new object[]{item.Volume, MakeDBPath(item)}).Delete();
        }

        protected override IEnumerable<string> GetExistingItems(string volume)
        {
            return (from file in data.Files where file.Volume == volume select Path.Combine(roots[volume], file.Path));
        }

        protected void RemoveUnusedTitles()
        {
            foreach (MediaDataSet.TitlesRow title in data.Titles)
            {
                if (title.GetFilesRows().Length == 0)
                {
                    title.Delete();
                }
            }
        }

        public void UpdateCaches()
        {
            foreach (var title in data.Titles)
            {
                DistributeCaches(title);
            }
        }

        public void DistributeCaches(MediaDataSet.TitlesRow title)
        {
            if (title.RowState == System.Data.DataRowState.Deleted)
                return;
            var items = (from f in title.GetFilesRows()
                         where f.RowState != System.Data.DataRowState.Deleted && roots.IsOnline(f.Volume)
                         group f by f.Volume into v
                         select new { Volume = v.Key, File = v.FirstOrDefault() });

            foreach (var item in items)
            {

                string filePath = Path.Combine(roots[item.Volume], item.File.Path);
                string titlePath = FindParentDir(title.Name, filePath);

                if (titlePath == null || !Directory.Exists(titlePath))
                    continue;

                foreach (var cache in caches)
                {
                    string inRoot = cache.FindExisting(titlePath);

                    if (inRoot != null && !cache.Contains(title))
                    {
                        // The disk contains the file but the cache does not
                        // cache it
                        cache.Save(title, inRoot);
                    }
                    else if (inRoot == null && cache.Contains(title) && DistributeMetadata)
                    {
                        // Cache contains the title, disk does not
                        // Save to disk
                        cache.Distribute(title, titlePath);
                    }


                }
            }
        }

        public static string FindParentDir(string targetDirName, string currentPath)
        {
            string subPath = currentPath.ToLower();
            while (!Path.GetFileName(subPath).Equals(targetDirName, StringComparison.CurrentCultureIgnoreCase) && subPath != null)
            {
                subPath = Path.GetDirectoryName(subPath);
            }
            return subPath;
        }

        public void ScanVolumes()
        {
            this.ScanVolumes(roots.Roots);
        }
    }
}
